package com.jasonzqshen.ifm.featureModelCore;

import java.util.Collection;
import java.util.LinkedList;

import org.w3c.dom.Element;

import com.jasonzqshen.ifm.collections.treeCollection.*;
import com.jasonzqshen.ifm.collections.treeCollection.factories.TreeNodeFactory;
import com.jasonzqshen.ifm.featureModelCore.arguments.*;
import com.jasonzqshen.ifm.featureModelCore.featureModelInterface.*;
import com.jasonzqshen.ifm.featureModelCore.shapes.*;
import com.jasonzqshen.ifm.utils.*;

public final class FeatureTreeNode extends TreeNode implements Feature {

    public static final TreeNodeFactory FACTORY = new TreeNodeFactory(
            FeatureTreeNode.class.getName()) {

        @Override
        public FeatureTreeNode constructNewInstance(Identifier id, Object[] args) {
            if (args == null || args.length != 1
                    || !(args[0] instanceof String)) {
                return new FeatureTreeNode(id);
            }

            String featureName = (String) args[0];
            FeatureTreeNode node = new FeatureTreeNode(id);
            node.featureName = featureName;
            return node;
        }

        @Override
        /**
         * XML parser
         * 
         * @param xelem
         * @param obj
         * @throws TreeCollectionException
         */
        public void xmlParser(Element elem, TreeObject treeObject) {
            if (!(treeObject instanceof FeatureTreeNode)) {
                return;
            }
            FeatureTreeNode newNode = (FeatureTreeNode) treeObject;

            newNode.featureName = elem.getAttribute(XML_NODE_NAME);
            newNode.annotation = elem.getAttribute(XML_ANNOTATION);

            newNode.rectangle = FMRectangle.parseXElem(elem);
        }

    };

    private static final String XML_NODE_NAME = "NodeName";

    private static final String XML_ANNOTATION = "Annotation";

    private String featureName;

    private String annotation;

    private FMRectangle rectangle;

    /**
     * Get identifier
     * 
     * @param id
     */
    public FeatureTreeNode(Identifier id) {
        super(id);
        featureName = FeatureModel.STRING_EMPTY;
        annotation = FeatureModel.STRING_EMPTY;

        rectangle = new FMRectangle();

    }

    /**
     * Get Parent Feature
     * 
     * @return
     */
    public Feature getParentFeature() {
        return this.getGroupRelationshipParent().getParentNode();
    }

    public FeatureTreeGroupRelationship getGroupRelationshipParent() {
        return (FeatureTreeGroupRelationship) this.parent;
    }

    /**
     * Get feature name
     */
    @Override
    public String getFeatureName() {
        return this.featureName;
    }

    /**
     * Set feature name
     */
    public void setFeatureName(String featureName) {
        FeatureNameChangedArgs args = new FeatureNameChangedArgs(this,
                featureName);
        this.treeOwner.beforeProcess(this, args);
        this.featureName = featureName;
        this.treeOwner.afterProcess(this, args);
    }

    /**
     * Get annotation.
     */
    @Override
    public String getAnnotation() {
        return this.annotation;
    }

    /**
     * Set annotation
     */
    public void setAnnotation(String annotation) {
        this.annotation = annotation;
    }

    /**
     * Get properties
     */
    @Override
    public Collection<FeatureNodeProperty> getProperties() {
        LinkedList<FeatureNodeProperty> properties = new LinkedList<FeatureNodeProperty>();
        for (NonRoot child : this.children.values()) {
            if (child instanceof FeatureNodeProperty) {
                properties.add((FeatureNodeProperty) child);
            }
        }
        return properties;
    }

    /**
     * Get Feature Tree Nodes
     */
    @Override
    public Collection<FeatureTreeNode> getChildrenNodes() {
        LinkedList<FeatureTreeNode> nodes = new LinkedList<FeatureTreeNode>();
        for (FeatureTreeGroupRelationship gRelationship : this
                .getChildrenGroupRelationship()) {
            nodes.addAll(gRelationship.getChildrenNodes());
        }
        return nodes;
    }

    /**
     * get children group relationship
     */
    @Override
    public Collection<FeatureTreeGroupRelationship> getChildrenGroupRelationship() {
        LinkedList<FeatureTreeGroupRelationship> gRelationshipes = new LinkedList<FeatureTreeGroupRelationship>();
        for (NonRoot child : this.children.values()) {
            if (child instanceof FeatureTreeGroupRelationship) {
                gRelationshipes.add((FeatureTreeGroupRelationship) child);
            }
        }
        return gRelationshipes;
    }

    /**
     * Get shape
     */
    @Override
    public FMRectangle getShape() {
        return this.rectangle;
    }

    /**
     * Set shape
     */
    @Override
    public void setShape(FMRectangle shape) {
        this.rectangle = shape;
    }

    /**
     * @throws TreeCollectionException
     * 
     */
    @Override
    public Element toXElem() throws TreeCollectionException {
        Element xelem = super.toXElem();
        xelem.setAttribute(XML_NODE_NAME, featureName);
        xelem.setAttribute(XML_ANNOTATION, annotation);

        if (this.rectangle != null) {
            rectangle.toXElem(xelem);
        }
        return xelem;
    }

    @Override
    public boolean equals(Object obj) {
        boolean flag = super.equals(obj);
        if (flag == false) {
            return flag;
        }
        if (!(obj instanceof FeatureTreeNode)) {
            return false;
        }

        FeatureTreeNode featureNode = (FeatureTreeNode) obj;
        return this.featureName.equals(featureNode.featureName)
                && this.annotation.equals(featureNode.annotation)
                && this.rectangle.equals(featureNode.rectangle);
    }

}
